/*
 * Copyright (c) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import {parse} from './intl-messageformat-parser/index.js' 
import {TYPE, SKELETON_TYPE,isLiteralElement,isArgumentElement, isNumberElement, isDateElement,isTimeElement, isSelectElement, isPluralElement,isPoundElement, isTagElement, isNumberSkeleton, isDateTimeSkeleton, createLiteralElement,createNumberElement} from './intl-messageformat-parser/types.js'
import {parseDateTimeSkeleton,convertNumberSkeletonToNumberFormatOptions} from './intl-messageformat-parser/skeleton.js'
const runCount = 400000;
const runCount_short = 10;
const runCount_middle = 500;


/**
 * Parse
*/
function parse_Test(){
    let input = `Hello, {name}! Today is {date, date, full}. You have {count, plural, =0 {no items} =1 {one item} other {# items}}, {level, select, beginner {beginner} intermediate {intermediate} advanced {advanced} other {unknown}} level. Your current balance is {balance, number, currency}. The temperature is {temperature, number} degrees. It's {weather, selectordinal, one {the #st} two {the #nd} few {the #rd} other {the #th}} day of the month. Are you interested in the following categories: {categories, select, technology {Technology} fashion {Fashion} food {Food} other {Other}}? For more information, visit our website at {website}. <tag> This is an XML-like tag. </tag> Your appointment time is {appointmentTime, time, short}.`
    let ast
    let startTime = getDate()
    for (let i = 0; i < runCount_short; i++) {
        ast = parse(input)
    }
    let endTime = getDate()
    let expected = `[{"type":0,"value":"Hello, "},{"type":1,"value":"name"},{"type":0,"value":"! Today is "},{"type":3,"style":"full","value":"date"},{"type":0,"value":". You have "},{"type":6,"pluralType":"cardinal","value":"count","offset":0,"options":{"=0":{"value":[{"type":0,"value":"no items"}]},"=1":{"value":[{"type":0,"value":"one item"}]},"other":{"value":[{"type":7},{"type":0,"value":" items"}]}}},{"type":0,"value":", "},{"type":5,"value":"level","options":{"beginner":{"value":[{"type":0,"value":"beginner"}]},"intermediate":{"value":[{"type":0,"value":"intermediate"}]},"advanced":{"value":[{"type":0,"value":"advanced"}]},"other":{"value":[{"type":0,"value":"unknown"}]}}},{"type":0,"value":" level. Your current balance is "},{"type":2,"style":"currency","value":"balance"},{"type":0,"value":". The temperature is "},{"type":2,"style":null,"value":"temperature"},{"type":0,"value":" degrees. It's "},{"type":6,"pluralType":"ordinal","value":"weather","offset":0,"options":{"one":{"value":[{"type":0,"value":"the "},{"type":7},{"type":0,"value":"st"}]},"two":{"value":[{"type":0,"value":"the "},{"type":7},{"type":0,"value":"nd"}]},"few":{"value":[{"type":0,"value":"the "},{"type":7},{"type":0,"value":"rd"}]},"other":{"value":[{"type":0,"value":"the "},{"type":7},{"type":0,"value":"th"}]}}},{"type":0,"value":" day of the month. Are you interested in the following categories: "},{"type":5,"value":"categories","options":{"technology":{"value":[{"type":0,"value":"Technology"}]},"fashion":{"value":[{"type":0,"value":"Fashion"}]},"food":{"value":[{"type":0,"value":"Food"}]},"other":{"value":[{"type":0,"value":"Other"}]}}},{"type":0,"value":"? For more information, visit our website at "},{"type":1,"value":"website"},{"type":0,"value":". "},{"type":8,"value":"tag","children":[{"type":0,"value":" This is an XML-like tag. "}]},{"type":0,"value":" Your appointment time is "},{"type":4,"style":"short","value":"appointmentTime"},{"type":0,"value":"."}]`
    if (JSON.stringify(ast) !== expected) {
        throw new Error('icu4j_parse error')
    }
    print(`icu4j_parse: ${endTime - startTime} ms`)
}

/**
 * isLiteralElement
*/
function isLiteralElement_Test() {
    let input = {type: TYPE.literal, value: 'Hello, John! Today is'};
    let typesResult
    let startTime = getDate()
    for (let i = 0; i < runCount; i++) {
        typesResult = isLiteralElement(input);
    }
    let endTime = getDate()
    if (typesResult !== true) {
        throw new Error('icu4j_isLiteralElement error')
    }
    print(`icu4j_isLiteralElement: ${endTime - startTime} ms`)
}

/**
 * isArgumentElement
*/
function isArgumentElement_Test() {
    let input = { type: TYPE.argument, value: 'website'};
    let typesResult
    let startTime = getDate()
    for (let i = 0; i < runCount; i++) {
        typesResult = isArgumentElement(input);
    }
    let endTime = getDate()
    if (typesResult !== true) {
        throw new Error('icu4j_isArgumentElement error')
    }
    print(`icu4j_isArgumentElement: ${endTime - startTime} ms`)
}

/**
 * isNumberElement
*/
function isNumberElement_Test() {
    let input = {type: TYPE.number, value: 'balance', style: 'currency'};
    let typesResult
    let startTime = getDate()
    for (let i = 0; i < runCount; i++) {
        typesResult = isNumberElement(input);
    }
    let endTime = getDate()
    if (typesResult !== true) {
        throw new Error('icu4j_isNumberElement error')
    }
    print(`icu4j_isNumberElement: ${endTime - startTime} ms`) 
}

/**
 * isDateElement
*/
function isDateElement_Test() {
    let input = { type: TYPE.date, value: 'date', style: 'full'};
    let typesResult
    let startTime = getDate()
    for (let i = 0; i < runCount; i++) {
        typesResult = isDateElement(input);
    }
    let endTime = getDate()
    if (typesResult !== true) {
        throw new Error('icu4j_isDateElement error')
    }
    print(`icu4j_isDateElement: ${endTime - startTime} ms`) 
}

/**
 * isTimeElement
*/
function isTimeElement_Test() {
    let input = {type: TYPE.time, style: "short", value:"appointmentTime"};
    let typesResult
    let startTime = getDate()
    for (let i = 0; i < runCount; i++) {
        typesResult = isTimeElement(input);
    }
    let endTime = getDate()
    if (typesResult !== true) {
        throw new Error('icu4j_isTimeElement error')
    }
    print(`icu4j_isTimeElement: ${endTime - startTime} ms`) 
}

/**
 * isSelectElement
*/
function isSelectElement_Test() {
    let input = { type: TYPE.select, value: "level", options:{beginner: {value: [{type: 0, value: "beginner"}]}, intermediate: { value :[{ type: 0, value: "intermediate"}]}, advanced: {value: [{type: 0, value: "advanced"}]}, other: { value: [{type: 0, value: "unknown"}]}}};
    let typesResult
    let startTime = getDate()
    for (let i = 0; i < runCount; i++) {
        typesResult = isSelectElement(input);
    }
    let endTime = getDate()
    if (typesResult !== true) {
        throw new Error('icu4j_isSelectElement error')
    }
    print(`icu4j_isSelectElement: ${endTime - startTime} ms`) 
}

/**
 * isPluralElement
*/
function isPluralElement_Test() {
    let input = {type: TYPE.plural, pluralType: "cardinal", value: "count", offset: 0, options: {"=0": {value:[{type:0,value:"no items"}]},"=1":{value: [{type: 0, value:"one item"}]},"other":{value:[{type:7},{type:0, value:" items"}]}}}
    let typesResult
    let startTime = getDate()
    for (let i = 0; i < runCount; i++) {
        typesResult = isPluralElement(input);
    }
    let endTime = getDate()
    if (typesResult !== true) {
        throw new Error('icu4j_isPluralElement error')
    }
    print(`icu4j_isPluralElement: ${endTime - startTime} ms`) 
}

/**
 * isPoundElement
*/
function isPoundElement_Test() {
    let input = {type: TYPE.pound};
    let typesResult
    let startTime = getDate() 
    for (let i = 0; i < runCount; i++) {
        typesResult = isPoundElement(input);
    }
    let endTime = getDate()
    if (typesResult !== true) {
        throw new Error('icu4j_isPoundElement error')
    }
    print(`icu4j_isPoundElement: ${endTime - startTime} ms`) 
}

/**
 * isTagElement
*/
function isTagElement_Test() {
    let input = {type: TYPE.tag, value:"tag", children:[{type:0,value:" This is an XML-like tag. "}]};
    let typesResult
    let startTime = getDate()
    for (let i = 0; i < runCount; i++) {
        typesResult = isTagElement(input);
    }
    let endTime = getDate()
    if (typesResult !== true) {
        throw new Error('icu4j_isTagElement error')
    }
    print(`icu4j_isTagElement: ${endTime - startTime} ms`)
}

/**
 * isNumberSkeleton
*/
function isNumberSkeleton_Test() {
    let input = { type: SKELETON_TYPE.number, tokens: [{stem: 'currency',  options: ['USD']}]};
    let typesResult
    let startTime = getDate()
    for (let i = 0; i < runCount; i++) {
        typesResult = isNumberSkeleton(input);
    }
    let endTime = getDate()
    if (typesResult !== true) {
        throw new Error('icu4j_isNumberSkeleton error')
    }
    print(`icu4j_isNumberSkeleton: ${endTime - startTime} ms`)
}

/**
 * isDateTimeSkeleton
*/
function isDateTimeSkeleton_Test() {
    let input = {type: SKELETON_TYPE.dateTime, pattern: 'yyyy-MM-dd'};
    let typesResult
    let startTime = getDate()
    for (let i = 0; i < runCount; i++) {
        typesResult = isDateTimeSkeleton(input);
    }
    let endTime = getDate()
    if (typesResult !== true) {
        throw new Error('icu4j_isDateTimeSkeleton error')
    }
    print(`icu4j_isDateTimeSkeleton: ${endTime - startTime} ms`)
}

/**
 * createLiteralElement
*/
function createLiteralElement_Test() {
    let str = `Remember to complete your tasks on time!`
    let typesResult
    let startTime = getDate()
    for (let i = 0; i < runCount; i++) {
        typesResult = createLiteralElement(str);
    }
    let endTime = getDate()
    if (typesResult.value !== str) {
        throw new Error('icu4j_createLiteralElement error')
    }
    print(`icu4j_createLiteralElement: ${endTime - startTime} ms`)
}

/**
 * createNumberElement
*/
function createNumberElement_Test() {
    let typesResult
    let startTime = getDate()
    for (let i = 0; i < runCount; i++) {
        typesResult = createNumberElement('1000', 'currency');
    }
    let endTime = getDate()
    if (typesResult.value !== '1000' && typesResult.style !== 'currency') {
        throw new Error('icu4j_createNumberElement error')
    }
    print(`icu4j_createNumberElement: ${endTime - startTime} ms`)
}

/**
 * parseDateTimeSkeleton
*/
function parseDateTimeSkeleton_Test() {
    let skeleton = 'yyyy-MM-dd EEEE a h:mm:ss z'
    let skeletonResult
    let startTime = getDate()
    for (let i = 0; i < 5000; i++) {
        skeletonResult = parseDateTimeSkeleton(skeleton);
    }
    let endTime = getDate()
    let expected = `{"year":"numeric","month":"2-digit","day":"2-digit","weekday":"short","hour12":true,"hourCycle":"h12","hour":"numeric","minute":"2-digit","second":"2-digit","timeZoneName":"short"}`
    if (JSON.stringify(skeletonResult) !== expected) {
        throw new Error('icu4j_parseDateTimeSkeleton error')
    }
    print(`icu4j_parseDateTimeSkeleton: ${endTime - startTime} ms`)
}

/**
 * convertNumberSkeletonToNumberFormatOptions
*/
function convertNumberSkeletonToNumberFormatOptions_Test() {
    let skeletonTokens = [{stem: 'currency',  options: ['USD']}];
    let skeletonResult
    let startTime = getDate()
    for (let i = 0; i < runCount; i++) {
        skeletonResult = convertNumberSkeletonToNumberFormatOptions(skeletonTokens);
    }
    let endTime = getDate()
    if (skeletonResult.style !== 'currency' && skeletonResult.currency !== 'USD') {
        throw new Error('icu4j_convertNumberSkeletonToNumberFormatOptions error')
    }
    print(`icu4j_convertNumberSkeletonToNumberFormatOptions: ${endTime - startTime} ms`)
}

function getDate() {
    return Date.now()
}

function runAllTest() {
    parse_Test()
    isLiteralElement_Test()
    isArgumentElement_Test()
    isNumberElement_Test()
    isDateElement_Test()
    isTimeElement_Test()
    isSelectElement_Test()
    isPluralElement_Test()
    isPoundElement_Test()
    isTagElement_Test()
    isNumberSkeleton_Test()
    isDateTimeSkeleton_Test()
    createLiteralElement_Test()
    createNumberElement_Test()
    parseDateTimeSkeleton_Test()
    convertNumberSkeletonToNumberFormatOptions_Test()
}
let loopCountForPreheat = 1;
for (let i = 0; i < loopCountForPreheat; i++) {
    runAllTest()
}

ArkTools.waitAllJitCompileFinish();

runAllTest()